package tripleo.nio.javanio;

/*
 * @(#)ChannelIO.java	1.2 04/07/26
 * 
 * Copyright (c) 2004 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * -Redistribution of source code must retain the above copyright notice, this
 *  list of conditions and the following disclaimer.
 * 
 * -Redistribution in binary form must reproduce the above copyright notice, 
 *  this list of conditions and the following disclaimer in the documentation
 *  and/or other materials provided with the distribution.
 * 
 * Neither the name of Sun Microsystems, Inc. or the names of contributors may 
 * be used to endorse or promote products derived from this software without 
 * specific prior written permission.
 * 
 * This software is provided "AS IS," without a warranty of any kind. ALL 
 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
 * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
 * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST 
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, 
 * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY 
 * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 
 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * 
 * You acknowledge that this software is not designed, licensed or intended
 * for use in the design, construction, operation or maintenance of any
 * nuclear facility.
 */

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.*;

/**
 * A helper class for properly sizing inbound byte buffers and
 * redirecting I/O calls to the proper SocketChannel call.
 * <P>
 * Many of these calls may seem unnecessary until you consider
 * that they are placeholders for the secure variant, which is much
 * more involved.  See ChannelIOSecure for more information.
 *
 * @author Brad R. Wetmore
 * @author Mark Reinhold
 * @version 1.2, 04/07/26
 */
public class ChannelIO {

	protected SocketChannel sc;

	/*
	 * All of the inbound request data lives here until we determine
	 * that we've read everything, then we pass that data back to the
	 * caller.
	 */
	protected ByteBuffer requestBB;
	static private int requestBBSize = 4096;

	protected ChannelIO(SocketChannel sc, boolean blocking)
	        throws IOException {
		this.sc = sc;
		sc.configureBlocking(blocking);
	}

	public static ChannelIO getInstance(SocketChannel sc, boolean blocking)
	        throws IOException {
		ChannelIO cio = new ChannelIO(sc, blocking);
		cio.requestBB = ByteBuffer.allocate(requestBBSize);

		return cio;
	}

	public SocketChannel getSocketChannel() {
		return sc;
	}

	/*
	 * Return a ByteBuffer with "remaining" space to work.  If you have to
	 * reallocate the ByteBuffer, copy the existing info into the new buffer.
	 */
	protected void resizeRequestBB(int remaining) {
		if (requestBB.remaining() < remaining) {
			// Expand buffer for large request
			ByteBuffer bb = ByteBuffer.allocate(requestBB.capacity() * 2);
			requestBB.flip();
			bb.put(requestBB);
			requestBB = bb;
		}
	}

	/*
	 * Perform any handshaking processing.
	 * <P>
	 * This variant is for Servers without SelectionKeys (e.g.
	 * blocking).
	 * <P>
	 * return true when we're done with handshaking.
	 */
	boolean doHandshake() throws IOException {
		return true;
	}

	/*
	 * Perform any handshaking processing.
	 * <P>
	 * This variant is for Servers with SelectionKeys, so that
	 * we can register for selectable operations (e.g. selectable
	 * non-blocking).
	 * <P>
	 * return true when we're done with handshaking.
	 */
	public boolean doHandshake(SelectionKey sk) throws IOException {
		return true;
	}

	/*
	 * Resize (if necessary) the inbound data buffer, and then read more
	 * data into the read buffer.
	 */
	public int read() throws IOException {
		/*
		* Allocate more space if less than 5% remains
		*/
		resizeRequestBB(requestBBSize / 20);
		return sc.read(requestBB);
	}

	/*
	 * All data has been read, pass back the request in one buffer.
	 */
	public ByteBuffer getReadBuf() {
		return requestBB;
	}

	/*
	 * Write the src buffer into the socket channel.
	 */
	public int write(ByteBuffer src) throws IOException {
		return sc.write(src);
	}

	/*
	 * Perform a FileChannel.TransferTo on the socket channel.
	 */
	long transferTo(FileChannel fc, long pos, long len) throws IOException {
		return fc.transferTo(pos, len, sc);
	}

	/*
	 * Flush any outstanding data to the network if possible.
	 * <P>
	 * This isn't really necessary for the insecure variant, but needed
	 * for the secure one where intermediate buffering must take place.
	 * <P>
	 * Return true if successful.
	 */
	public boolean dataFlush() throws IOException {
		return true;
	}

	/*
	 * Start any connection shutdown processing.
	 * <P>
	 * This isn't really necessary for the insecure variant, but needed
	 * for the secure one where intermediate buffering must take place.
	 * <P>
	 * Return true if successful, and the data has been flushed.
	 */
	public boolean shutdown() throws IOException {
		return true;
	}

	/*
	 * Close the underlying connection.
	 */
	public void close() throws IOException {
		sc.close();
	}

}
